﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Security;
using System.Windows.Interop;
using System.Windows.Media;
using System.Collections.Specialized;

namespace UIControls
{

    /// <summary>
    /// Control to select a specific date
    /// </summary>
    [TemplatePart(Name = "PART_Dates", Type = typeof(Selector))]
    public class TimePicker : ComboBox, INotifyPropertyChanged
    {
        #region const
        const string CurrentlySelectedDateStringPropertyName = "CurrentlySelectedDateString";
        const string StartTimePropertyName = "StartTime";
        #endregion

        //buttons for the back and forward
        private Selector datesList;

        public bool AllowNull { get; set; }

        #region properties and events

        /// <summary>
        /// Gets and sets a string that represents the selected date
        /// </summary>
        public string CurrentlySelectedDateString
        {
            get
            {
                if (SelectedTime.TotalSeconds >= 0)
                {
                    string value = SelectedTime.ToString();

                    string h = (value.ToString().Substring(0, 2));
                    string m = (value.ToString().Substring(3, 2));

                    return h + ":" + m;
                }
                else
                {
                    return "不设置";
                }
            }
            set
            {
                try
                {
                    int h = int.Parse(value.Substring(0, 2));
                    int m = int.Parse(value.Substring(3, 2));

                    SelectedTime = TimeSpan.FromMinutes(h * 60 + m);
                }
                catch
                {
                    SelectedTime = TimeSpan.FromSeconds(0);
                }
            }
        }


        #region 选中时间

        /// <summary>
        /// Gets and sets the currently viewed date
        /// </summary>
        public TimeSpan SelectedTime
        {
            get { return (TimeSpan)GetValue(SelectedTimeProperty); }
            set { SetValue(SelectedTimeProperty, value); }
        }
        /// <summary>
        /// Gets and sets the currently viewed date
        /// </summary>
        public static readonly DependencyProperty SelectedTimeProperty =
            DependencyProperty.Register("SelectedTime", typeof(TimeSpan), typeof(TimePicker),
            new UIPropertyMetadata(TimeSpan.FromSeconds(0), CurrentlySelectedDatePropertyChanged));

        /// <summary>
        /// 选中时间发先变化
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="e"></param>
        static void CurrentlySelectedDatePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            TimePicker picker = (TimePicker)obj;

            new System.Threading.Thread(() =>
            {
                //延时触发变更通知。目的是在界面其它元素更新后便于计算
                System.Threading.Thread.Sleep(10);

                picker.Dispatcher.BeginInvoke(new Action(() =>
                {
                    picker.OnDateChanged(picker.SelectedTime, (TimeSpan)e.OldValue);
                    picker.OnPropertyChanged(new PropertyChangedEventArgs(CurrentlySelectedDateStringPropertyName));

                    if (picker.datesList != null)
                    {
                        foreach (TimeCell t in picker.datesList.Items)
                        {
                            if (t.TimeSpan == picker.SelectedTime)
                            {
                                picker.datesList.SelectedItem = t;
                                break;
                            }
                        }
                    }

                }));
            }).Start();
        }

        #endregion

        #region 最大时间
        public TimeSpan MaxTime
        {
            get { return (TimeSpan)GetValue(MaxTimeProperty); }
            set { SetValue(MaxTimeProperty, value); }
        }

        /// <summary>
        /// Gets and sets the currently viewed date
        /// </summary>
        public static readonly DependencyProperty MaxTimeProperty =
            DependencyProperty.Register("MaxTime", typeof(TimeSpan), typeof(TimePicker),
            new UIPropertyMetadata(TimeSpan.FromMinutes(1439), null));

        #endregion

        #region 开始时间
        public TimeSpan StartTime
        {

            get { return (TimeSpan)GetValue(StartTimeProperty); }
            set { SetValue(StartTimeProperty, value); }
        }

        /// <summary>
        /// Gets and sets the currently viewed date
        /// </summary>
        public static readonly DependencyProperty StartTimeProperty =
            DependencyProperty.Register("StartTime", typeof(TimeSpan), typeof(TimePicker),
            new UIPropertyMetadata(TimeSpan.FromSeconds(0), StartTimePropertyChanged));

        //raise the property changed for CurrentlySelectedDateProperty
        static void StartTimePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            TimePicker picker = (TimePicker)obj;
            //picker.OnDateChanged(picker.SelectedTime, (TimeSpan)e.OldValue);
            picker.OnPropertyChanged(new PropertyChangedEventArgs(StartTimePropertyName));
            
            //更新项目
            picker.ReBindListOfDays();
        }

        #endregion

        /// <summary>
        /// Event for the DateSelectionChanged raised when the date changes
        /// </summary>
        public static readonly RoutedEvent SelectedDateChangedEvent = EventManager.RegisterRoutedEvent("SelectedDateChanged",
            RoutingStrategy.Bubble, typeof(DateSelectedChangedEventHandler), typeof(TimePicker));

        /// <summary>
        /// Event for the DateSelectionChanged raised when the date changes
        /// </summary>
        public event DateSelectedChangedEventHandler SelectedDateChanged
        {
            add { AddHandler(SelectedDateChangedEvent, value); }
            remove { RemoveHandler(SelectedDateChangedEvent, value); }
        }

        #endregion

        /// <summary>
        /// Static constructor
        /// </summary>
        static TimePicker()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TimePicker), new FrameworkPropertyMetadata(typeof(TimePicker)));
        }


        #region INotifyPropertyChanged Members

        /// <summary>
        /// Event raised when a property is changed
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises the property changed event
        /// </summary>
        /// <param name="e">The arguments to pass</param>
        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }

        #endregion

        #region Overrides of control

        /// <summary>
        /// override to get the templated controls
        /// </summary>
        public override void OnApplyTemplate()
        {
            //Focus the popup if it exists in the Control template
            Popup popup = GetTemplateChild("Popup") as Popup;
            if (popup != null)
            {
                popup.Opened += delegate
                {
                    popup.Focus();
                };
            }

            datesList = GetTemplateChild("PART_Dates") as Selector;

            datesList.SelectionChanged += DatesListSelectionChanged;

            ReBindListOfDays();
        }

        //on selected item cahnge of the selector control
        void DatesListSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListBox list = datesList as ListBox;

            if (datesList.SelectedIndex != -1)
            {
                SelectedTime = GetTimeFromCell((TimeCell)datesList.SelectedItem);
            }
            this.IsDropDownOpen = false;
        }

        TimeSpan GetTimeFromCell(TimeCell c)
        {
            return c.TimeSpan;
        }

        //rebinds to the dates
        void ReBindListOfDays()
        {
            if (datesList != null)
            {
                List<TimeCell> listOfTimes = new List<TimeCell>();
                int N = 24;

                int start = this.StartTime.Hours;
                if (start < 0) start = 0;

                for (int i = start; i < N; i++)
                {
                    listOfTimes.Add(new TimeCell(TimeSpan.FromMinutes(i * 60)));
                }
                if (this.AllowNull == true)
                {
                    listOfTimes.Add(new TimeCell(TimePicker.NullSpan));
                }
                datesList.ItemsSource = listOfTimes;
            }
        }

        public static TimeSpan NullSpan
        {
            get
            {
                return TimeSpan.FromMinutes(-2);
            }
        }

        private void OnDateChanged(TimeSpan newDate, TimeSpan oldDate)
        {
            if (newDate.TotalSeconds >= 0 && this.MaxTime.TotalSeconds >= 0)
            {
                if (this.MaxTime != null)
                {
                    if (newDate > MaxTime)
                    {
                        MessageBox.Show("开始时间不能大于结束时间", "系统提示", MessageBoxButton.OK, MessageBoxImage.Error);
                        if (oldDate > MaxTime) this.SelectedTime = MaxTime;
                        else this.SelectedTime = oldDate;
                        return;
                    }
                }
                if (this.StartTime != null && this.StartTime.Hours != 0)
                {
                    if (newDate < StartTime)
                    {
                        MessageBox.Show("开始时间不能大于结束时间", "系统提示", MessageBoxButton.OK, MessageBoxImage.Error);
                        this.SelectedTime = oldDate;
                        return;
                    }
                }
            }
            
            DateSelectedChangedRoutedEventArgs args =
                new DateSelectedChangedRoutedEventArgs(SelectedDateChangedEvent);
            args.NewDate = newDate;
            args.OldDate = oldDate;
            RaiseEvent(args); ;
        }

        #endregion
    }

}